import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Scanner;

/**
 * This section looks over the Assembler that is the main control point of the
 * Assembler. All interactions with the user are handled here. It is also
 * responsible for initiating the different steps in parsing the input file to
 * creating the output file. Read from file, run pass one, runs pass 2, outputs
 * files, or error to console.
 */
public class AssemblerImproved {

	/**
	 *The Assembler at first will look for the filename (given by the user)
	 * from the arguments given to it when it is called. If no arguments are
	 * given when it is called, the Assembler catches this within an if-else
	 * statement and will print to the console with a message asking the user
	 * for a file name. A try-catch block then calls Pass1 to start reading the
	 * input file. Any exceptions thrown by Pass1 is caught here and handled in
	 * the catch block. Also in the try-catch block is the calls to the Output
	 * class that would produce the output files of the Assembler.
	 * 
	 * @param String
	 *            [] args ?String array containing the filename as the first
	 *            element.
	 *@return Nothing
	 *@throws Nothing
	 */
	public static void main(String[] args) {
		// If input file is not provided at command line
		// then prompt user to provide one.
		String inputFile;
		Scanner in = new Scanner(System.in);
		StringBuilder objString = new StringBuilder();
		StringBuilder lstString = new StringBuilder();

		if (args.length == 0) {
			System.out.print("Please input file name:");
			inputFile = in.nextLine();
		} else {
			inputFile = args[0];
		}

		// remove file extension
		int fileNameLength = inputFile.lastIndexOf('.');
		if (fileNameLength == -1) {
			fileNameLength = inputFile.length();
		}
		String fileName = String.copyValueOf(inputFile.toCharArray(), 0,
				fileNameLength);

		// pass the fileName to the Class that handles read-in files.
		try {
			Pass1.readLines(inputFile);
			Lines.checkOverflow();
			
			//added for lab3.
			ENTTable.checkValid();

			// print object code.
			if (Lines.size() > 0) {
				
				if(Lines.size() < 3) {
					throw new AssembleException(0,"The program has no meaningful or excutable instructions ");
				}
				
				for (int i = 0; i < Lines.size(); i++) {
					if (!Lines.get(i).getOps().equals(".END")) {
						String objCode = Output.toObj(Lines.get(i));
						
						if (objCode != null) {
							objString.append(objCode);
							objString.append("\n");
						}
						if(Lines.get(i).getOps().equals(".ORIG")) {
							objString.append(ENTTable.toObj());
							//objString.append(EXTTable.toObj());
						}
					} else if(Lines.get(i).getOps().equals(".EXT") || Lines.get(i).getOps().equals(".ENT")) {
						//do nothing.
					}else {
						int j = 0;
						while (LitTable.size() > j) {
							objString.append(LitTable.toObj(j));
							objString.append("\n");
							j++;
						}
						objString.append(Output.toObj(Lines.get(i)));
						objString.append("\n");
					}
				}
			}

			// print listing code.
			for (int i = 0; i < Lines.size(); i++) {
				String lstCode = Output.tolst(Lines.get(i));
				if(lstCode!=null) {
					lstString.append(lstCode);
					lstString.append("\n");
				}
				
			}
			// then literals need to be output too.
			for (int i = 0; i < LitTable.size(); i++) {
				lstString.append(LitTable.tolst(i));
				lstString.append("\n");
			}

			// create files
			FileWriter objFileWriter = new FileWriter(fileName + ".obj");
			FileWriter lstFileWriter = new FileWriter(fileName + ".lst");
			objFileWriter.write(objString.toString());
			lstFileWriter.write(lstString.toString());
			// System.out.println(objString.toString());//Here for debug purpose
			// System.out.println(lstString.toString());//same as above
			objFileWriter.close();
			lstFileWriter.close();
			System.out.println("Files created.");

		} catch (FileNotFoundException e) {
			System.out.print("***Error***:Input file not found.");
		} catch (AssembleException e) {
			System.out.println(e);
		} catch (IOException e) {
			System.out.print("***Error***:Output file was interrupted.");
		}

		in.close();

	}
}